import { MatcherForPicker, OS, UARule } from "./meta";
import versionCompare from "../versionCompare";
import { range, sample } from "lodash-es";

const chromeVersions: string[] = [
  "120.0.6099.109",
  "120.0.6099.129",
  "120.0.6099.130",
  "120.0.6099.234",
  "120.0.6099.235",
  "119.0.6045.105",
  "119.0.6045.106",
  "119.0.6045.66",
  "119.0.6045.199",
  "119.0.6045.200",
  "121.0.6167.141",
  "121.0.6167.185",
  "121.0.6167.85",

  // 以下仅为demo
  "87.0.0.1",
  "87.0.0.2",
  "88.0.0.1",
  "88.0.0.2",
  "89.0.0.1",
  "89.0.0.2",
  "89.0.0.1",
  "89.0.0.2",
];
const iOSVersions: string[] = [...chromeVersions];

const filterChromeVersions = (start: string, end: string) =>
  chromeVersions.filter(
    (v) => versionCompare(v, start) >= 0 || versionCompare(v, end) < 0,
  );

export const commonBrowserPicker: UARule["browser"]["picker"] = (
  values,
  matcher,
) =>
  sample(
    values.filter((v) => {
      const match =
        matcher instanceof RegExp
          ? (val: string) => val.match(matcher)
          : matcher;
      return match(v);
    }),
  ) as string;
export const commonPicker: UARule["webkit"]["picker"] = (values) =>
  sample(values) as string;

export const rules: UARule[] = [
  {
    os: OS.Win,
    versionForClient: "10",
    versionForUA: { values: ["Windows NT 10.0; Win64; x64"] },
    webkit: {
      values: ["AppleWebKit/537.36"],
    },
    browser: {
      values: chromeVersions.filter(
        (v) => versionCompare(v, "119") >= 0 || versionCompare(v, "122") < 0,
      ),
    },
    safari: {
      values: ["Safari/537.36"],
    },
  },
  {
    os: OS.Win,
    versionForClient: "11",
    versionForUA: { values: ["Windows NT 10.0; Win64; x64"] },
    webkit: {
      values: ["AppleWebKit/537.36"],
    },
    browser: {
      values: chromeVersions.filter(
        (v) => versionCompare(v, "119") >= 0 || versionCompare(v, "122") < 0,
      ),
    },
    safari: {
      values: ["Safari/537.36"],
    },
  },
  {
    os: OS.Win,
    versionForClient: "8.1",
    versionForUA: {
      values: [
        "Windows NT 6.3; Win64; x64",
        "Windows NT 6.3; Win32; x86",
        "Windows NT 6.3; WOW64",
      ],
    },
    webkit: {
      values: ["AppleWebKit/537.36"],
    },
    browser: {
      values: chromeVersions.filter(
        (v) => versionCompare(v, "84") >= 0 || versionCompare(v, "120") < 0,
      ),
    },
    safari: {
      values: ["Safari/537.36"],
    },
  },
  {
    os: OS.Win,
    versionForClient: "8",
    versionForUA: {
      values: [
        "Windows NT 6.2; Win64; x64",
        "Windows NT 6.2; Win32; x86",
        "Windows NT 6.2; WOW64",
      ],
    },
    webkit: {
      values: ["AppleWebKit/537.36"],
    },
    browser: {
      values: chromeVersions.filter(
        (v) => versionCompare(v, "84") >= 0 || versionCompare(v, "120") < 0,
      ),
    },
    safari: {
      values: ["Safari/537.36"],
    },
  },
  {
    os: OS.Win,
    versionForClient: "7",
    versionForUA: {
      values: [
        "Windows NT 6.1; Win64; x64",
        "Windows NT 6.1; Win32; x86",
        "Windows NT 6.1; WOW64",
      ],
    },
    webkit: {
      values: ["AppleWebKit/537.36"],
    },
    browser: {
      values: chromeVersions.filter(
        (v) => versionCompare(v, "84") >= 0 || versionCompare(v, "120") < 0,
      ),
    },
    safari: {
      values: ["Safari/537.36"],
    },
  },
  {
    os: OS.Mac,
    versionForClient: "10.15.7",
    versionForUA: {
      values: ["Macintosh; Intel Mac OS X 10_15_7"],
    },
    webkit: {
      values: ["AppleWebKit/537.36"],
    },
    browser: {
      values: chromeVersions.filter(
        (v) => versionCompare(v, "119") >= 0 || versionCompare(v, "122") < 0,
      ),
    },
    safari: {
      values: ["Safari/537.36"],
    },
  },
  {
    os: OS.Mac,
    versionForClient: "10.14.6",
    versionForUA: {
      values: ["Macintosh; Intel Mac OS X 10_14_6"],
    },
    webkit: {
      values: ["AppleWebKit/537.36"],
    },
    browser: {
      values: chromeVersions.filter(
        (v) => versionCompare(v, "87") >= 0 || versionCompare(v, "90") < 0,
      ),
    },
    safari: {
      values: ["Safari/537.36"],
    },
  },
  {
    os: OS.Mac,
    versionForClient: "10.13.6",
    versionForUA: {
      values: ["Macintosh; Intel Mac OS X 10_13_6"],
    },
    webkit: {
      values: ["AppleWebKit/537.36"],
    },
    browser: {
      values: chromeVersions.filter(
        (v) => versionCompare(v, "87") >= 0 || versionCompare(v, "90") < 0,
      ),
    },
    safari: {
      values: ["Safari/537.36"],
    },
  },
  {
    os: OS.Mac,
    versionForClient: "10.12.6",
    versionForUA: {
      values: ["Macintosh; Intel Mac OS X 10_12_6"],
    },
    webkit: {
      values: ["AppleWebKit/537.36"],
    },
    browser: {
      values: chromeVersions.filter(
        (v) => versionCompare(v, "87") >= 0 || versionCompare(v, "90") < 0,
      ),
    },
    safari: {
      values: ["Safari/537.36"],
    },
  },
  {
    os: OS.Mac,
    versionForClient: "10.11.6",
    versionForUA: {
      values: ["Macintosh; Intel Mac OS X 10_11_6"],
    },
    webkit: {
      values: ["AppleWebKit/537.36"],
    },
    browser: {
      values: chromeVersions.filter(
        (v) => versionCompare(v, "87") >= 0 || versionCompare(v, "90") < 0,
      ),
    },
    safari: {
      values: ["Safari/537.36"],
    },
  },
  {
    os: OS.Mac,
    versionForClient: "10.10.5",
    versionForUA: {
      values: ["Macintosh; Intel Mac OS X 10_10_5"],
    },
    webkit: {
      values: ["AppleWebKit/537.36"],
    },
    browser: {
      values: chromeVersions.filter(
        (v) => versionCompare(v, "87") >= 0 || versionCompare(v, "90") < 0,
      ),
    },
    safari: {
      values: ["Safari/537.36"],
    },
  },
  {
    os: OS.Linux,
    versionForClient: "20.04.3",
    displayedVersion: "X11; Linux x86_64",
    versionForUA: {
      values: ["X11; Linux x86_64"],
    },
    webkit: {
      values: ["AppleWebKit/537.36"],
    },
    browser: {
      values: chromeVersions.filter(
        (v) => versionCompare(v, "119") >= 0 || versionCompare(v, "122") < 0,
      ),
    },
    safari: {
      values: ["Safari/537.36"],
    },
  },
  {
    os: OS.Linux,
    versionForClient: "20.04.1",
    displayedVersion: "Linux i686",
    versionForUA: {
      values: ["X11; Linux i686"],
    },
    webkit: {
      values: ["AppleWebKit/537.36"],
    },
    browser: {
      values: filterChromeVersions("119", "122"),
    },
    safari: {
      values: ["Safari/537.36"],
    },
  },
  ...range(9, 15).map((n) => ({
    os: OS.Android,
    versionForClient: n.toString(),
    versionForUA: {
      values: ["Linux; Android 10; K"],
    },
    webkit: {
      values: ["AppleWebKit/537.36"],
    },
    browser: {
      values: filterChromeVersions("119", "122"),
    },
    safari: {
      values: ["Mobile Safari/537.36"],
    },
  })),
  ...range(14, 18).map((v) => ({
    os: OS.IOS,
    versionForClient: v.toString(),
    versionForUA: {
      values: range(0, 10).map(
        (i) => `iPhone; CPU iPhone OS ${v}_${i} like Mac OS X`,
      ),
    },
    webkit: {
      values: ["AppleWebKit/605.1.15"],
    },
    browser: {
      values: iOSVersions.filter(
        (v) => versionCompare(v, 119) >= 0 || versionCompare(v, 122) < 0,
      ),
    },
    safari: {
      values: ["Mobile/15E148 Safari/604.1"],
    },
  })),
];

export const makeAllUserAgents = () => {
  const ans: string[] = [];
  for (const { os, versionForUA, webkit, browser, safari } of rules) {
    for (const osVersion of versionForUA.values) {
      for (const webkitVersion of webkit.values) {
        for (const browserVersion of browser.values) {
          for (const safariVersion of safari.values) {
            ans.push(
              [
                `Mozilla/5.0`,
                `(${osVersion}) ${webkitVersion}`,
                `(KHTML, like Gecko) ${os === OS.IOS ? "CriOS" : "Chrome"}/${browserVersion}`,
                safariVersion,
              ].join(" "),
            );
          }
        }
      }
    }
  }
  return ans;
};

export const makeUA = (params: {
  os: OS;
  osVersionForClient: string;
  browserFilter?: MatcherForPicker;
}) => {
  const rule = rules.find(
    (r) =>
      r.os === params.os && r.versionForClient === params.osVersionForClient,
  );
  if (!rule) throw new Error("不存在匹配的规则");

  const webkit = (rule.webkit.picker ?? commonPicker)(rule.webkit.values);
  const browserVersion = (rule.browser.picker ?? commonBrowserPicker)(
    rule.browser.values,
    params.browserFilter || (() => true),
  );
  const safari = (rule.safari.picker ?? commonBrowserPicker)(
    rule.safari.values,
    () => true,
  );

  const versionForUA = (rule.versionForUA.picker ?? commonPicker)(
    rule.versionForUA.values,
  );

  return [
    `Mozilla/5.0`,
    `(${versionForUA})`,
    webkit,
    `(KHTML, like Gecko)`,
    `${rule.os === OS.IOS ? "CriOS" : "Chrome"}/${browserVersion}`,
    safari,
  ].join(" ");
};

export const makeRandomUserAgent = () => {
  const { os, versionForUA, webkit, browser, safari } =
    rules[Math.floor(Math.random() * rules.length)];
  const osVersion = sample(versionForUA.values) as string;
  const webkitVersion = sample(webkit.values) as string;
  const browserVersion = sample(browser.values);
  const safariVersion = sample(safari.values);
  return [
    `Mozilla/5.0`,
    `(${osVersion}) ${webkitVersion}`,
    `(KHTML, like Gecko) ${os === OS.IOS ? "CriOS" : "Chrome"}/${browserVersion}`,
    safariVersion,
  ].join(" ");
};
